/**
* File Name: condition_product_consumer.c
* Auther: Jichang
* Environment: Fedora 7 server
*/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<pthread.h>

// linklist is shared data, need to be protected by mutex.
struct msg {
	struct msg *next;
	int num;
};
struct msg *head; // head node.

// static init. A condition var and A mutex.
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void *consumer(void *p)
{
	struct msg *mp;
	for(;;) {
		pthread_mutex_lock(&lock);
		while(head == NULL) {
			// head==NULL indicate no node.
			pthread_cond_wait(&has_product, &lock);
		}
		mp = head;
		head = mp->next; // simulate consume one.
		pthread_mutex_unlock(&lock);

		printf("-Consumer %lu --- %d\n", pthread_self(), mp->num);
		free(mp);
		sleep(rand() % 5);
	}
}

void *producer(void *p)
{ 
	struct msg *mp;
	for(;;) {
		mp = malloc(sizeof(struct msg));
		mp->num = rand() % 1000 + 1; // simulate produce.
		printf("-Produce ---%d\n", mp->num);

		pthread_mutex_lock(&lock);
		mp->next = head;
		head = mp; // add into.
		pthread_mutex_unlock(&lock);

		// wake up condition-thread.
		pthread_cond_signal(&has_product);
		sleep(rand() % 5);
	}
}

int main(int argc, char *argv[])
{
	pthread_t pid, cid;
	srand(time(NULL));

	pthread_create(&pid, NULL, producer, NULL);
	pthread_create(&cid, NULL, consumer, NULL);
	
	pthread_join(pid, NULL);
	pthread_join(cid, NULL);

	return 0;
}

